﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using BCMS.Business.Implementation;
using BCMS.Business.DataContract;
using BCMS.DAL.MySQL;
using BCMS.Settings;
using BCMS.FrontEnd.DataContract;
using System.Diagnostics;
namespace BCMS.Forms
{
    public partial class frmRelease : Form
    {
        DALclient client = new DALclient();
        private frmMain pForm;
        int releaseId = 0;

        public frmRelease(frmMain main)
        {
            this.Font = SystemFonts.MessageBoxFont;
            this.pForm = main;
            InitializeComponent();

            //DateTime firstDayOfTheMonth = new DateTime(dtStart.Value.Year, dtStart.Value.Month, 1);
            //dtExpire.Value = firstDayOfTheMonth.AddMonths(7).AddDays(-1);
            dtExpire.Value = dtStart.Value.AddMonths(6);
            loadKindList(string.Empty);
            loadTargetList(string.Empty);
        }

        public frmRelease()
        {
            this.Font = SystemFonts.MessageBoxFont;
            InitializeComponent();

            //DateTime firstDayOfTheMonth = new DateTime(dtStart.Value.Year, dtStart.Value.Month, 1);
            //dtExpire.Value = firstDayOfTheMonth.AddMonths(7).AddDays(-1);
            dtExpire.Value = dtStart.Value.AddMonths(6);

            loadKindList(string.Empty);
            loadTargetList(string.Empty);

        }

        public frmRelease(ReleaseUI item, frmMain main)
        {
            this.Font = SystemFonts.MessageBoxFont;
            InitializeComponent();
            this.pForm = main;
            if (item != null)
            {
                txtRCode.Text = item.RCode;
                txtRLow.Value = item.RLow;
                txtRHigh.Value = item.RHigh;
                txtName.Text = item.Name;
                txtParValue.Text = item.ParValue.ToString();
                txtDetail.Text = item.Detail;
                txtNote.Text = item.Note;
                txtQtty.Value = item.Qtty;
                loadTargetList(item.Target);
                loadKindList(item.Kind);
                btnRun.Text = "Cập nhật";
                releaseId = item.ReleaseId;

                txtQtty.Enabled = false;
                txtParValue.ReadOnly = true;
                txtRCode.ReadOnly = true;
                txtRLow.ReadOnly = true;
                txtRHigh.ReadOnly = true;
                dtStart.Enabled = false;
                dtExpire.Enabled = false;
            }
        }

        private bool validateInput()
        {
            if (txtRCode.Text.Trim().Length.Equals(0))
            {
                GlobalVars.ShowError("Mã số không hợp lệ.");
                txtRCode.Focus();
                return false;
            }
            if (txtParValue.Value <= 0 || txtRLow.Value.Equals(0) || txtRHigh.Value.Equals(0))
            {
                GlobalVars.ShowError("Mệnh giá không hợp lệ.");
                txtParValue.Focus();
                return false;
            }

            if (txtQtty.Value.Equals(0) || txtRLow.Value.Equals(0) || txtRHigh.Value.Equals(0))
            {
                GlobalVars.ShowError("Số series không hợp lệ");
                txtRCode.Focus();
                return false;
            }

            if (txtRLow.Value > txtRHigh.Value)
            {
                GlobalVars.ShowError("Số series không hợp lệ");
                txtRCode.Focus();
                return false;
            }

            if (dtExpire.Value.Date < dtStart.Value.Date)
            {
                GlobalVars.ShowError("Giá trị ngày hết hạn không hợp lệ so với ngày phát hành.");
                dtExpire.Focus();
                return false;
            }

            if (txtName.Text.Trim().Length == 0)
            {
                GlobalVars.ShowError("Tên đợt phát hành không hợp lệ.");
                txtRCode.SelectAll();
                return false;
            }
            return true;
        }

        private List<CouponInfo> getCoupons(int releaseID)
        {
            List<CouponInfo> list = new List<CouponInfo>();
            try
            {
                for (long i = txtRLow.Value; i <= txtRHigh.Value; i++)
                {
                    CouponInfo coupon = new CouponInfo();
                    coupon.Serial = string.Format("{0}-{1}", txtRCode.Text, i);
                    coupon.StartDate = dtStart.Value.Date;
                    coupon.ExpireDate = dtExpire.Value.Date;
                    coupon.ParValue = txtParValue.Value;
                    coupon.Status = (int)CStatus.Normal;
                    coupon.Note = string.Empty;
                    coupon.ReleaseId = releaseID;
                    coupon.IsCanceled = false;

                    list.Add(coupon);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error: " + ex.Message);
                txtRCode.SelectAll();
                return null;
            }

            return list;
        }

        private void resetForms()
        {
            btnRun.Enabled = true;
            txtRHigh.Value = 0;
            txtRLow.Value = 0;
            txtQtty.Value = 0;
            txtDetail.Text = string.Empty;
            txtNote.Text = string.Empty;
            cbKind.SelectedIndex = 0;
            cbTarget.SelectedIndex = 0;

            lblStatus.Text = string.Empty;
            lblSoFar.Text = "0";
            lblPercent.Text = "0";
            lblTotal.Text = "0";
            progress.Value = 0;
            grpProcessInfo.Enabled = false;

            txtRCode.SelectAll();
        }

        private void dtStart_ValueChanged(object sender, EventArgs e)
        {
            updateName();
            //DateTime firstDayOfTheMonth = new DateTime(dtStart.Value.Year, dtStart.Value.Month, 1);
            // March 2011 [REQ change]: expire date auto to 7 month after release date. 
            //dtExpire.Value = firstDayOfTheMonth.AddMonths(7).AddDays(-1);
            // Jan 2012 [REQ change]: expire date auto to 6 month after release date.
            dtExpire.Value = dtStart.Value.AddMonths(6);
        }

        private void dtExpire_ValueChanged(object sender, EventArgs e)
        {
            updateName();
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void frmRelease_Load(object sender, EventArgs e)
        {
            List<string> details = client.getDetailSuggest();
            if (details != null)
            {
                AutoCompleteStringCollection customSrc = new AutoCompleteStringCollection();
                foreach (string item in details)
                    customSrc.Add(item);
                txtDetail.AutoCompleteCustomSource = customSrc;
                txtDetail.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
            }
            updateName();
        }

        private void loadTargetList(string select)
        {
            List<KeyValuePair<RTarget, string>> targets = new List<KeyValuePair<RTarget, string>>();
            cbTarget.Items.Clear();
            targets.Add(new KeyValuePair<RTarget, string>(RTarget.CUSTOMER, "Khách hàng"));
            targets.Add(new KeyValuePair<RTarget, string>(RTarget.PARTNER, "Đối tác"));
            targets.Add(new KeyValuePair<RTarget, string>(RTarget.STAFF, "Nhân viên"));
            targets.Add(new KeyValuePair<RTarget, string>(RTarget.OTHER, "Khác"));
            cbTarget.DataSource = targets;
            cbTarget.ValueMember = "Key";
            cbTarget.DisplayMember = "Value";
            if (!string.IsNullOrEmpty(select))
                cbTarget.Text = select;
        }

        private void loadKindList(string select)
        {
            List<KeyValuePair<RKind, string>> kinds = new List<KeyValuePair<RKind, string>>();
            cbKind.Items.Clear();
            kinds.Add(new KeyValuePair<RKind, string>(RKind.SELL, "Bán"));
            kinds.Add(new KeyValuePair<RKind, string>(RKind.DISCOUNT, "Chiết khấu"));
            kinds.Add(new KeyValuePair<RKind, string>(RKind.GIFT, "Quà tặng"));
            kinds.Add(new KeyValuePair<RKind, string>(RKind.OTHER, "Khác"));
            cbKind.DataSource = kinds;
            cbKind.ValueMember = "Key";
            cbKind.DisplayMember = "Value";
            if (!string.IsNullOrEmpty(select))
                cbKind.Text = select;
        }

        private void txtNumCode_Leave(object sender, EventArgs e)
        {
            updateQtty();
            updateName();
        }

        private void updateName()
        {
            try
            {
                StringBuilder name = new StringBuilder();
                if (cbTarget.SelectedValue != null)
                {
                    switch ((int)((RTarget)cbTarget.SelectedValue))
                    {
                        case (int)RTarget.CUSTOMER:
                            name.Append("C");
                            break;
                        case (int)RTarget.PARTNER:
                            name.Append("P");
                            break;
                        case (int)RTarget.STAFF:
                            name.Append("S");
                            break;
                        case (int)RTarget.OTHER:
                            name.Append("O");
                            break;
                    }
                }
                name.Append("_");
                if (cbKind.SelectedValue != null)
                {
                    switch ((int)((RKind)cbKind.SelectedValue))
                    {
                        case (int)RKind.SELL:
                            name.Append("S");
                            break;
                        case (int)RKind.DISCOUNT:
                            name.Append("D");
                            break;
                        case (int)RKind.GIFT:
                            name.Append("G");
                            break;
                        case (int)RKind.OTHER:
                            name.Append("O");
                            break;
                    }
                }
                name.Append(dtStart.Value.ToString("_ddMMyyyy_"));
                name.Append(txtParValue.Value.ToString());
                name.Append(dtExpire.Value.ToString("_ddMMyyyy"));

                txtName.Text = name.ToString();
            }
            catch
            {
                return;
            }

        }

        private void updateQtty()
        {
            if (txtRLow.Value > txtRHigh.Value)
            {
                MessageBox.Show("Số series sau phải lớn hơn");
                txtRLow.SelectAll();
                return;
            }
            txtQtty.Value = txtRHigh.Value - txtRLow.Value + 1;
        }

        private void cbTarget_SelectedIndexChanged(object sender, EventArgs e)
        {
            updateName();
        }

        private void txtValue_Leave(object sender, EventArgs e)
        {
            updateName();
        }

        private void txtRLow_Leave(object sender, EventArgs e)
        {
            if (!txtRLow.Value.Equals(0) || !txtRHigh.Value.Equals(0))
            {
                if (txtQtty.Value.Equals(0))
                {
                    txtQtty.Value = txtRHigh.Value - txtRLow.Value + 1;
                }
                else
                {
                    if ((txtRLow.Value > 0) && (txtRHigh.Value.Equals(0)))
                        txtRHigh.Value = txtRLow.Value + txtQtty.Value - 1;
                    else if ((txtRHigh.Value > 0) && (txtRLow.Value.Equals(0)))
                        txtRLow.Value = txtRHigh.Value - txtQtty.Value + 1;
                    else if ((txtRLow.Value > 0) && (txtRHigh.Value > 0))
                        txtRHigh.Value = txtRLow.Value + txtQtty.Value;
                    else
                        txtQtty.Value = txtRHigh.Value - txtRLow.Value + 1;
                }
            }
            else
            {
                txtQtty.Value = txtRHigh.Value - txtRLow.Value + 1;
            }

        }

        private void txtRHigh_Leave(object sender, EventArgs e)
        {
            if (!txtRLow.Value.Equals(0) || !txtRHigh.Value.Equals(0))
            {
                if (txtQtty.Value.Equals(0))
                {
                    txtQtty.Value = txtRHigh.Value - txtRLow.Value + 1;
                }
                else
                {
                    if ((txtRLow.Value > 0) && (txtRHigh.Value.Equals(0)))
                        txtRHigh.Value = txtRLow.Value + txtQtty.Value - 1;
                    else if ((txtRHigh.Value > 0) && (txtRLow.Value.Equals(0)))
                        txtRLow.Value = txtRHigh.Value - txtQtty.Value + 1;
                    else
                        txtQtty.Value = txtRHigh.Value - txtRLow.Value + 1;
                }
            }
            else
            {
                txtQtty.Value = txtRHigh.Value - txtRLow.Value + 1;
            }
        }

        class ShowProgressArgs : EventArgs
        {
            public string Coupon;
            public int Total;
            public int SoFar;

            public ShowProgressArgs(string coupon, int total, int soFar)
            {
                this.Coupon = coupon;
                this.Total = total;
                this.SoFar = soFar;
            }
        }

        delegate void ShowProgressHandler(object sender, ShowProgressArgs e);

        void ShowProgress(object sender, ShowProgressArgs e)
        {
            // Make sure we're on the right thread
            if (this.InvokeRequired == false)
            {
                lblTotal.Text = e.Total.ToString("N0");
                lblStatus.Text = e.Coupon;
                lblSoFar.Text = e.SoFar.ToString("N0");
                lblPercent.Text = Convert.ToInt32(e.SoFar * 100 / e.Total).ToString() + "%";

                progress.Maximum = e.Total;
                progress.Value = e.SoFar;

                // Check for completion
                if (e.SoFar.Equals(e.Total))
                {
                    SortableBindingList<ReleaseUI> releaseList = pForm.grvReleases.DataSource as SortableBindingList<ReleaseUI>;
                    if (releaseList != null)
                    {
                        ReleaseUI item = new ReleaseUI();
                        item.ReleaseId = releaseId;
                        item.RCode = txtName.Text;
                        item.StartDate = dtStart.Value.Date;
                        item.ExpireDate = dtExpire.Value.Date;
                        item.ParValue = Convert.ToDecimal(txtParValue.Value);
                        item.Qtty = txtQtty.Value;
                        item.Target = cbTarget.Text;
                        item.Detail = txtDetail.Text;
                        item.Note = txtNote.Text;
                        item.RCode = txtRCode.Text;
                        item.RLow = txtRLow.Value;
                        item.RHigh = txtRHigh.Value;
                        item.Kind = cbKind.Text;
                        item.TotalValue = item.Qtty * item.ParValue;

                        releaseList.Insert(0, item);
                        pForm.updateReleaseSummary();
                    }
                    else
                        pForm.updateReleaseList();

                    releaseId = 0;
                    GlobalVars.ShowInfo("Phát hành [THÀNH CÔNG] đợt phát hành: " + txtName.Text);
                    resetForms();
                }
            }
            // Transfer control to correct thread
            else
            {
                ShowProgressHandler showProgress = new ShowProgressHandler(ShowProgress);
                Invoke(showProgress, new object[] { sender, e });
            }
        }

        void updateData(List<CouponInfo> coupons)
        {
            try
            {
                object sender = System.Threading.Thread.CurrentThread;
                ShowProgressArgs e = new ShowProgressArgs(string.Empty, coupons.Count, 0);

                // Show progress (ignoring Cancel so soon)
                ShowProgress(sender, e);

                if (coupons.Count > 0)
                {
                    for (int i = 0; i < coupons.Count; i++)
                    {
                        StaticDAL.InsertNewCoupon(coupons[i]);

                        // Show progress (checking for Cancel)
                        e.Coupon = coupons[i].Serial;
                        e.SoFar = i + 1;
                        ShowProgress(sender, e);
                    }
                }
            }
            catch (Exception ex)
            {
                GlobalVars.ShowError("Có [LỖI] trong quá trình phát hành. \n\nError: " + ex.Message);
                deleteFailRelease(releaseId);
                MessageBox.Show("Đã [HỦY] dữ liệu trong quá trình phát hành lỗi?", Params.CONFIRM, MessageBoxButtons.YesNo, MessageBoxIcon.Question);

            }

        }

        delegate void updateCouponDelegate(List<CouponInfo> coupons);

        private void btnRun_Click(object sender, EventArgs e)
        {
            DALclient client = new DALclient();

            updateName();
            if (!validateInput())
                return;
            else
            {
                if (!btnRun.Text.Equals("Cập nhật"))
                {
                    grpProcessInfo.Enabled = true;
                    btnRun.Enabled = false;
                    releaseId = client.insertRelease(txtName.Text, dtStart.Value.Date,
                                           dtExpire.Value.Date, txtRHigh.Value - txtRLow.Value + 1,
                                           Convert.ToDecimal(txtParValue.Value),
                                           (int)((RTarget)cbTarget.SelectedValue),
                                           txtDetail.Text, txtNote.Text, (int)((RKind)cbKind.SelectedValue),
                                           txtRCode.Text, txtRLow.Value, txtRHigh.Value);

                    // Async delegate method
                    updateCouponDelegate calcPi = new updateCouponDelegate(updateData);
                    calcPi.BeginInvoke(getCoupons(releaseId), null, null);
                }
                else
                {
                    client.updateReleaseById(releaseId, txtName.Text, dtStart.Value.Date,
                                            dtExpire.Value.Date, txtRHigh.Value - txtRLow.Value + 1,
                                            Convert.ToDecimal(txtParValue.Value),
                                            (int)((RTarget)cbTarget.SelectedValue),
                                            txtDetail.Text, txtNote.Text,
                                            (int)((RKind)cbKind.SelectedValue),
                                            txtRCode.Text, txtRLow.Value, txtRHigh.Value);
                    SortableBindingList<ReleaseUI> releaseList =
                                pForm.grvReleases.DataSource as SortableBindingList<ReleaseUI>;

                    int seletectIndex = pForm.grvReleases.SelectedRows[0].Index;
                    releaseList[seletectIndex].Name = txtName.Text;
                    releaseList[seletectIndex].Note = txtNote.Text;
                    releaseList[seletectIndex].Detail = txtDetail.Text;
                    releaseList[seletectIndex].Kind = cbKind.Text;
                    releaseList[seletectIndex].Target = cbTarget.Text;
                    this.Close();
                }
            }

        }

        private void deleteFailRelease(int releaseId)
        {
            try
            {
                DALclient client = new DALclient();
                client.deleteReleaseById(releaseId);
                client.deleteCouponByReleaseId(releaseId);
            }
            catch { }
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            const int WM_KEYDOWN = 0x100;
            if (msg.Msg == WM_KEYDOWN)
            {
                if (keyData == Keys.Escape)
                {
                    this.Close();
                    return true;
                }

            }
            return base.ProcessCmdKey(ref msg, keyData);
        }
    }
}
